import Vue from "vue"
import Vuex from "vuex"
import {
  INCREMENT,
  DECREMENT,
  INCREMENT_COUNT,
  ADD_STUDENT,
  INFO_UPDATE,
  A_INFO_UPDATE
} from "./mutations-type";

// 第一步: 引入插件后, 调用Vue.use() 来进行install Vuex
Vue.use(Vuex)

const ModuleA = {
  state: {
    name : "zhangsan"
  },
  getters : {
    fullName(state) {
      return state.name + 111
    },
    fullName2(state, getters) {
      return getters.fullName + 222
    },
    // 除了基本的写法外, 模块中的getters中的函数还有第三个参数, 为 rootState, 指向根的state
    fullName3(state,getters,rootState) {
      return getters.fullName2 + rootState.count
    }
  },
  mutations : {
    nameUpdate(state, payload) {
      state.name = payload
    }
  },
  actions : {
    // context 意为上下文 所以这里指向这个模块
    AnameUpdate(context,payload) {
      setTimeout(() => {
        // console.log(context);
        context.commit("nameUpdate", payload)
      },1000)
    }
  }
}


// 第二步: 创建Vuex实例: 注意这里创建的是 Vuex中的Store实例
const store = new Vuex.Store({
  state : {
    count : 100,
    students : [
      {id: 110, name: "xiaoLam", age:18 },
      {id: 111, name: "kobe", age: 20},
      {id:112, name: "suoer", age: 23},
      {id:113, name: "yangcong", age: 12}
    ],
    info : { id : 102, name : "fanghuonv", age : 16 }
  },
  // 创建mutations 对象
  mutations : {
    // mutations 中的方法中默认会传入一个state的参数, 这个参数就是上面定义的state对象
    [INCREMENT](state) {
      state.count++
    },
    [DECREMENT](state) {
      state.count--
    },
    // 如果在mutations更新数据的时候, 携带一些参数的时候
    [INCREMENT_COUNT](state, count) {
      // 下文的 payload 指 count形参
      // 普通的提交风格接收参数, 这个 payload 就是传入的参数
      // state.count += count

      // 一个包含type属性的对象提交的时候, 这个payload就不是传入的参数了, 而是整个对象
      console.log(count); // {type: "incrementCount", count: 5}
      // 要获得传入的参数, 则是 payload.count
      state.count += count.count
    },

    // 如果参数的个数不是一个的时候, 我们可以传入一个对象
    [ADD_STUDENT](state,student) {
      state.students.push(student)
    },

    
    [INFO_UPDATE](state) {
      // 如果给state中的对象属性修改值, 这个操作是响应式的, 因为修改的属性提前在state种初始化了
      state.info.name = "huixinge";

      // 如果给state中的对象添加新的属性, 这个操作不是响应式的, 因为这个新属性并没有提前在state中初始化
      // state.info["address"] = "jisichang"
      // 如果要想这个操作也变成响应式的话, 就要使用Vue.set(要修改的数组或对象, Number/String, 修改后的值)
      // Vue.set(state.info, "address", "jisichang") 

      // 如果给state中的对象删除属性, 这个操作也不是响应式的
      // delete state.info.id;
      // 如果想要这个操作也变成响应式的话, 就要使用Vue.delete(要修改的数组或对象, Number/String)
      // Vue.delete(state.info, "id")

      // Vue.set() 和 Vue.delete() 这两个方法内部会将 要修改的属性也一起添加到Vue的响应式系统里面了 


      // 如果在mutations中使用异步操作的话, devtools不能监控修改, 那就无法追踪是哪个组件修改了state共享数据
      // 这里使用定时器模拟异步操作
      /* setTimeout(() => {
        state.info.name = "huixinge";
      },1000) */
      // devtools无法监控异步操作修改的state共享数据， 所以vue官方规定异步操作都应该在actions中完成, 同步操作都应该在mutations中完成
    }
  },
  actions : {
    // 在actions中编写方法, 跟在mutations中编写方法差不多, 但是方法中传入的第一个参数并不是state, 而是 context
    // context意为 上下文, 可以理解为store这个对象
    // 如果想要传入参数, 也是跟mutations中的方法一样, 也是有普通方式, 和传入一个包含type属性的对象方式
    /* [A_INFO_UPDATE](context) {
      setTimeout(() => {
        // 注意, 不能再actions的方法中更新store的状态, 要记住一点, 更新store状态的唯一方式是mutations中的方法
        // 所以这里做的操作是使用 commit 提交
        context.commit(INFO_UPDATE)
      },1000)
    } */

    // 需求, 需要异步操作完成后, 给组件返回一个信息
    // 第一种方式, 通过组件传参的时候传入一个函数, 在actions中进行异步操作, 异步操作完成后回调这个函数
    /* [A_INFO_UPDATE](context, payload) {
      setTimeout(() => {
        // 注意, 不能再actions的方法中更新store的状态, 要记住一点, 更新store状态的唯一方式是mutations中的方法
        // 所以这里做的操作是使用 commit 提交
        context.commit(INFO_UPDATE)
        console.log(payload.message);
        payload.finsh();
      },1000)
    } */

    // 第一种方式不够优雅, vue官方推荐我们通过 return 一个new Promise 对象来实现
    [A_INFO_UPDATE](context, payload) {
      // 在这里return 出去的是回到组件那里的
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          context.commit(INFO_UPDATE)
          console.log(payload.message);
          resolve("完成了完成了");
        },1000)
      })
    }
  },
  getters : {
    // 在我们需要将共享数据进行处理后再展示在页面的情况下, 就需要使用getters对象, 相当于计算属性computed
    // getters中的方法也是有一个state参数, 指向state对象
    powerCount(state) {
      return state.count * state.count
    },
    // 需求1, 过滤state中的students, 取出年龄大于15的
    getAge15(state) {
      return state.students.filter(students => students.age > 15)
    },
    // 需求2, 获得年龄大于15的student的个数
    getAge15Num(state, getters) {
      // return state.students.filter(students => students.age > 15).length
      // getters对象中的方法, 除了state这个参数外, 还有getters参数, 这个参数指向getters对象
      // 所以上面的写法可以写成
      return getters.getAge15.length
    },
    // 需求3, 想要通过用户输入的年龄, 来决定输出大于该年龄的student
    // 要达到这个需求的话, 需要在方法中返回一个函数, 具体如下
    // 思路是return出去一个函数, 这个函数有一个形参, 这个形参由用户来决定
    getAge(state, getters) {
      return function (age) {
        return state.students.filter(students => students.age > age)
      }
    }
  },
  modules : {
    ModuleA
  }

})

// 第三步: 导出
export default store